prepare-root: Move /etc handling into library
authorColin Walters <walters@verbum.org>
Tue, 24 Jun 2025 20:39:00 +0000 (16:39 -0400)
committerColin Walters <walters@verbum.org>
Tue, 24 Jun 2025 21:04:59 +0000 (17:04 -0400)
Prep for soft reboots.

Signed-off-by: Colin Walters <walters@verbum.org>
src/libotcore/otcore-prepare-root.c
src/libotcore/otcore.h
src/switchroot/ostree-prepare-root.c

index 3efdf576ba1207a725256ce2b63d321d233179e2..5add90770e000cc6689e722d9748e37b494dfdfb 100644 (file)
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <ostree-core.h>
 #include <ostree-repo-private.h>
+#include <sys/mount.h>
 
 #ifdef HAVE_COMPOSEFS
 #include <libcomposefs/lcfs-mount.h>
@@ -34,6 +35,8 @@
 #define BINDING_KEYPATH "/etc/ostree/initramfs-root-binding.key"
 // The kernel argument to configure composefs
 #define CMDLINE_KEY_COMPOSEFS "ostree.prepare-root.composefs"
+// The key in the config for etc
+#define ETC_KEY "etc"
 
 static bool
 proc_cmdline_has_key_starting_with (const char *cmdline, const char *key)
@@ -362,6 +365,63 @@ composefs_error_message (int errsv)
 
 #endif
 
+/**
+ * otcore_mount_etc:
+ *
+ * Mount /etc for a deployment, assuming that the current process working directory is the source.
+ */
+gboolean
+otcore_mount_etc (GKeyFile *config, GVariantBuilder *metadata_builder, const char *mount_target,
+                  GError **error)
+{
+  gboolean etc_transient = FALSE;
+  if (!ot_keyfile_get_boolean_with_default (config, ETC_KEY, OTCORE_PREPARE_ROOT_TRANSIENT_KEY,
+                                            FALSE, &etc_transient, error))
+    return glnx_prefix_error (error, "Failed to parse etc.transient value");
+
+  g_autofree char *target_etc = g_build_filename (mount_target, "etc", NULL);
+  if (etc_transient)
+    {
+      const char *ovldir = "/run/ostree/transient-etc";
+
+      g_variant_builder_add (metadata_builder, "{sv}", OTCORE_RUN_BOOTED_KEY_TRANSIENT_ETC,
+                             g_variant_new_string (ovldir));
+
+      // Our lower directory is usr/etc.
+      g_autofree char *lowerdir = g_build_filename (mount_target, "usr/etc", NULL);
+      // Standard overlayfs tempdirs
+      g_autofree char *upperdir = g_build_filename (ovldir, "upper", NULL);
+      g_autofree char *workdir = g_build_filename (ovldir, "work", NULL);
+
+      struct
+      {
+        const char *path;
+        int mode;
+      } subdirs[] = { { ovldir, 0700 }, { upperdir, 0755 }, { workdir, 0755 } };
+      for (int i = 0; i < G_N_ELEMENTS (subdirs); i++)
+        {
+          if (mkdirat (AT_FDCWD, subdirs[i].path, subdirs[i].mode) < 0)
+            return glnx_throw_errno_prefix (error, "Failed to create dir %s", subdirs[i].path);
+        }
+
+      g_autofree char *ovl_options
+          = g_strdup_printf ("lowerdir=%s,upperdir=%s,workdir=%s", lowerdir, upperdir, workdir);
+      if (mount ("overlay", target_etc, "overlay", MS_SILENT, ovl_options) < 0)
+        return glnx_throw_errno_prefix (error, "failed to mount transient etc overlayfs");
+    }
+  else
+    {
+      /* Bind-mount /etc (at deploy path), and remount as writable. */
+      if (mount ("etc", target_etc, NULL, MS_BIND | MS_SILENT, NULL) < 0)
+        return glnx_throw_errno_prefix (error, "failed to prepare /etc bind-mount at %s",
+                                        target_etc);
+      if (mount (target_etc, target_etc, NULL, MS_BIND | MS_REMOUNT | MS_SILENT, NULL) < 0)
+        return glnx_throw_errno_prefix (error, "failed to make writable /etc bind-mount at %s",
+                                        target_etc);
+    }
+  return TRUE;
+}
+
 gboolean
 otcore_mount_rootfs (ComposefsConfig *composefs_config, GVariantBuilder *metadata_builder,
                      gboolean root_transient, const char *root_mountpoint, const char *deploy_path,
index 378878df3fcf8351f584b3ddfbf594f24e0d6d1d..01468b1f7a5785bde7b2bf5ca320fb344274f004 100644 (file)
@@ -99,6 +99,9 @@ gboolean otcore_mount_rootfs (ComposefsConfig *composefs_config, GVariantBuilder
                               const char *deploy_path, const char *mount_target,
                               bool *out_using_composefs, GError **error);
 
+gboolean otcore_mount_etc (GKeyFile *config, GVariantBuilder *metadata_builder,
+                           const char *mount_target, GError **error);
+
 // Our directory with transient state (eventually /run/ostree-booted should be a link to
 // /run/ostree/booted)
 #define OTCORE_RUN_OSTREE "/run/ostree"
@@ -128,6 +131,7 @@ gboolean otcore_mount_rootfs (ComposefsConfig *composefs_config, GVariantBuilder
 #define OTCORE_PREPARE_ROOT_COMPOSEFS_KEY "composefs"
 #define OTCORE_PREPARE_ROOT_ENABLED_KEY "enabled"
 #define OTCORE_PREPARE_ROOT_KEYPATH_KEY "keypath"
+#define OTCORE_PREPARE_ROOT_TRANSIENT_KEY "transient"
 
 // The file written in the initramfs which contains an a{sv} of metadata
 // from ostree-prepare-root.
index 7f350412fca0473957f953206f119154bd88c78b..8cdfbaa7947dba96921bce5f71fb470e08b4c1d2 100644 (file)
@@ -81,8 +81,6 @@
 
 /* This key configures the / mount in the deployment root */
 #define ROOT_KEY "root"
-#define ETC_KEY "etc"
-#define TRANSIENT_KEY "transient"
 
 #define OSTREE_PREPARE_ROOT_DEPLOYMENT_MSG \
   SD_ID128_MAKE (71, 70, 33, 6a, 73, ba, 46, 01, ba, d3, 1a, f8, 88, aa, 0d, f7)
@@ -188,8 +186,8 @@ main (int argc, char *argv[])
   gboolean sysroot_readonly = FALSE;
   gboolean root_transient = FALSE;
 
-  if (!ot_keyfile_get_boolean_with_default (config, ROOT_KEY, TRANSIENT_KEY, FALSE, &root_transient,
-                                            &error))
+  if (!ot_keyfile_get_boolean_with_default (config, ROOT_KEY, OTCORE_PREPARE_ROOT_TRANSIENT_KEY,
+                                            FALSE, &root_transient, &error))
     return FALSE;
 
   // We always parse the composefs config, because we want to detect and error
@@ -306,51 +304,8 @@ main (int argc, char *argv[])
    * the deployment needs to be created and remounted as read/write. */
   if (sysroot_readonly || using_composefs || root_transient)
     {
-      gboolean etc_transient = FALSE;
-      if (!ot_keyfile_get_boolean_with_default (config, ETC_KEY, TRANSIENT_KEY, FALSE,
-                                                &etc_transient, &error))
-        errx (EXIT_FAILURE, "Failed to parse etc.transient value: %s", error->message);
-
-      static const char *tmp_sysroot_etc = TMP_SYSROOT "/etc";
-      if (etc_transient)
-        {
-          char *ovldir = "/run/ostree/transient-etc";
-
-          g_variant_builder_add (&metadata_builder, "{sv}", OTCORE_RUN_BOOTED_KEY_TRANSIENT_ETC,
-                                 g_variant_new_string (ovldir));
-
-          char *lowerdir = "usr/etc";
-          if (using_composefs)
-            lowerdir = TMP_SYSROOT "/usr/etc";
-
-          g_autofree char *upperdir = g_build_filename (ovldir, "upper", NULL);
-          g_autofree char *workdir = g_build_filename (ovldir, "work", NULL);
-
-          struct
-          {
-            const char *path;
-            int mode;
-          } subdirs[] = { { ovldir, 0700 }, { upperdir, 0755 }, { workdir, 0755 } };
-          for (int i = 0; i < G_N_ELEMENTS (subdirs); i++)
-            {
-              if (mkdirat (AT_FDCWD, subdirs[i].path, subdirs[i].mode) < 0)
-                err (EXIT_FAILURE, "Failed to create dir %s", subdirs[i].path);
-            }
-
-          g_autofree char *ovl_options
-              = g_strdup_printf ("lowerdir=%s,upperdir=%s,workdir=%s", lowerdir, upperdir, workdir);
-          if (mount ("overlay", tmp_sysroot_etc, "overlay", MS_SILENT, ovl_options) < 0)
-            err (EXIT_FAILURE, "failed to mount transient etc overlayfs");
-        }
-      else
-        {
-          /* Bind-mount /etc (at deploy path), and remount as writable. */
-          if (mount ("etc", tmp_sysroot_etc, NULL, MS_BIND | MS_SILENT, NULL) < 0)
-            err (EXIT_FAILURE, "failed to prepare /etc bind-mount at /sysroot.tmp/etc");
-          if (mount (tmp_sysroot_etc, tmp_sysroot_etc, NULL, MS_BIND | MS_REMOUNT | MS_SILENT, NULL)
-              < 0)
-            err (EXIT_FAILURE, "failed to make writable /etc bind-mount at /sysroot.tmp/etc");
-        }
+      if (!otcore_mount_etc (config, &metadata_builder, TMP_SYSROOT, &error))
+        errx (EXIT_FAILURE, "Failed to mount etc: %s", error->message);
     }
 
   /* Prepare /usr.